﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;

namespace MsTestUtilities.SolutionAnalysis
{
    public enum OutputType
    {
        Exe,
        Library
    }

    public enum TestType
    {
        NotTest,
        UnitTest,
        OtherTestType
    }

    public interface IProject
    {
        string Path { get; }

        string Name { get; }
    }

    public class CsProject : IProject
    {           
        private CsProject()
        {            
        }       

        public string Path { get; private set; }

        public string Name { get; private set; }

        public PropertyGroup ProjectPropertyGroup { get; private set; }

        public static CsProject LoadFromXml(string msBuildXml)
        {
            var content = XElement.Parse(msBuildXml);

            var project = new CsProject();

            var propertyGroups = content
                .Elements(MsBuildXml.Namespace + "PropertyGroup")
                .Select(propertyGroupXml => new PropertyGroup(propertyGroupXml))
                .ToList();

            var items = content
                .Elements(MsBuildXml.Namespace + "ItemGroup")
                .SelectMany(group => group.Elements().Select(i => new Item(project, i)))
                .ToList();            

            var classifier = new ItemGroupClassifier(project);
            classifier.AddRange(items);

            project.ProjectPropertyGroup = propertyGroups.First();
               project.References = classifier.ItemGroups.Reference;
               project.ProjectReferences = classifier.ItemGroups.ProjectReference;
               project.ContentFiles = classifier.ItemGroups.Content;

            project._buildConfigurations = propertyGroups
                    .Where(g => BuildConfiguration.IsBuildConfiguration(g))
                    .Select(g => BuildConfiguration.FromPropertyGroup(project, g))
                    .ToList();

            return project;
        }

        public static CsProject LoadFromFile(string projectPath)
        {
            var content = File.ReadAllText(projectPath);
            var project = LoadFromXml(content);
            project.Path = projectPath;
            project.Name = System.IO.Path.GetFileNameWithoutExtension(projectPath);
            return project;
        }

        public string DefaultConfiguration
        {
            get { return ProjectPropertyGroup.GetElementValue("Configuration"); }
        }

        public string DefaultPlatform
        {
            get { return ProjectPropertyGroup.GetElementValue("Platform"); }
        }

        public Version TargetFrameworkVersion
        {
            get { 
                var versionText = ProjectPropertyGroup.GetElementValue("TargetFrameworkVersion");
                return new Version(versionText.Substring(1));
            }
        }

        public string RootNamespace
        {
            get { return ProjectPropertyGroup.GetElementValue("RootNamespace"); }
        }

        public string AssemblyName
        {
            get { return ProjectPropertyGroup.GetElementValue("AssemblyName"); }
        }

        public ItemGroup<ContentFile> ContentFiles { get; private set; }

        public ItemGroup<Reference> References { get; private set; }
        
        public ItemGroup<ProjectReference> ProjectReferences { get; private set;}        

        private OutputType? outputType;
        public OutputType OutputType
        {
            get
            {
                if (outputType == null)
                {
                    outputType = (OutputType)Enum.Parse(typeof(OutputType), ProjectPropertyGroup.GetElementValue("OutputType"));
                }

                return outputType.Value;
            }
        }

        private TestType testType;
        public TestType TestType
        {
            get
            {
                var testTypeString = ProjectPropertyGroup.GetElementValue("TestProjectType");
                if (testTypeString == null)
                {
                    testType = TestType.NotTest;
                }
                else
                {
                    if (!Enum.TryParse<TestType>(testTypeString, out testType))
                    {
                        testType = TestType.OtherTestType;
                    }
                }

                return testType;
            }
        }

        private List<BuildConfiguration> _buildConfigurations;
        public IEnumerable<BuildConfiguration> BuildConfigurations
        {
            get { return _buildConfigurations; }
        }        
    }
}
